package com.tansun.ruledata.service.impl;

import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.Collection;
import java.util.Collections;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.LinkedHashSet;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Properties;
import java.util.Set;

import org.kie.api.KieBase;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.ResourceUtils;

import com.alibaba.fastjson.JSON;
import com.tansun.rule.config.AppConfiguration;
import com.tansun.rule.pojo.EnterPoint;
import com.tansun.rule.utils.AppCacheInfo;
import com.tansun.rule.utils.MClass;
import com.tansun.rule.utils.StringUtils;
import com.tansun.ruledata.data.entity.DeployVersionInfo;
import com.tansun.ruledata.data.model.RuleBusinessInfo;
import com.tansun.ruledata.data.service.BussinessSynchService;
import com.tansun.ruledata.data.service.RuleResourceLoadService;
import com.tansun.ruledata.service.RuleDataCompileService;
import com.tansun.ruledata.sessionpool.RuleDataPooledSessionFactory;
import com.tansun.ruledata.sessionpool.SessionDataPool;

@Service("ruleDataCompileService")
public class RuleDataCompileServiceImpl implements RuleDataCompileService {

	@Autowired
	private BussinessSynchService bussinessSynchService;
	@Autowired
	private RuleResourceLoadService ruleResourceLoadService;
	/**
	 * 获取规则、规则调用点，规则参数信息
	 * @param projectCode
	 * @param enterPoint
	 * @return
	 */
	
	/**
	 * 获取规则、规则调用点，规则参数信息
	 * 该方法针对表名称中存在前缀rule_exe的表，这些包为执行表，是决策引擎部署时实时加载的数据，
	 * 只要在这些表里的数据都是正式的加载到执行器中,虽然是在同一个库中，但是与配置表分离，实现数据隔离
	 * @param projectCode
	 * @param enterPoint
	 * @return
	 */
	public RuleBusinessInfo getRuleBusinessInfo2(String projectCode, String enterPoint){
		RuleBusinessInfo ruleInfo = new RuleBusinessInfo();
		String timeStamp = this.bussinessSynchService.getDeploymentTimeStamp(projectCode, enterPoint);
		//数据模型数据
		Map<String, MClass> metaMap= this.bussinessSynchService.findMapping(projectCode,timeStamp);
		//调用点数据
		Map<String,EnterPoint> eMap = this.bussinessSynchService.findEnterPoint(projectCode,enterPoint,timeStamp);
		//规则数据
		Map<String,Collection<DeployVersionInfo>> conMap = this.bussinessSynchService.findDeployRuleVersionByTimestamp(projectCode,enterPoint,timeStamp);
		ruleInfo.setCurrTimeStamp(timeStamp);
		//无需每次加载每个点都去加载
//		Map<String,KieBase>  kieMap =	AppCacheInfo.kieMap.get(projectCode);
//		if (kieMap != null) {
//		   kieMap.clear();
//		}
//		ruleResourceLoadService.loadRuleFunctionDrl(projectCode,timeStamp);
//		ruleResourceLoadService.loadProjectRefeDrl(projectCode,timeStamp);
//        ruleResourceLoadService.loadProjectPmml(projectCode,timeStamp);
//        ruleResourceLoadService.loadProjectPmmlRefData(projectCode,timeStamp);		
		Collection<DeployVersionInfo>  list= conMap.get(enterPoint);
		ruleInfo.setMetaMap(metaMap);
		ruleInfo.setEnterMap(eMap);
		ruleInfo.setList(list);
		return ruleInfo;
	}
	

	/**
	 * 该方法针对交行总行，本质在于读取数据库中Rule_EXE开头的执行表
	 * 将获取规则、规则调用点，规则参数信息的数据进行缓存
	 * @param projectCode
	 * @param enterPoint
	 * @return
	 */
	public void prepareDataToCacheRuleExe(RuleBusinessInfo ruleInfo, String projectCode, String enterPoints) throws Exception {
		String[] pointArg = StringUtils.split(enterPoints, ";");
		for (String enterPoint : pointArg) {
			if(StringUtils.isEmpty(enterPoint))
				continue;
			if(ruleInfo==null) {
				//该方法针对表名称中存在前缀rule_exe的表，这些包为执行表，是决策引擎部署时实时加载的数据，
				//只要在这些表里的数据都是正式的加载到执行器中,虽然是在同一个库中，但是与配置表分离，实现数据隔离
				ruleInfo = this.getRuleBusinessInfo2(projectCode, enterPoint);
				AppConfiguration.dateTimeMap.put(projectCode+"_"+enterPoint, ruleInfo.getCurrTimeStamp());
			}
			if (ruleInfo.getEnterMap() != null && !ruleInfo.getEnterMap().isEmpty()){
				Map<String,EnterPoint> pMap = AppConfiguration.ruleEnterMap.get(projectCode);
				if (pMap == null){
					pMap  = new  HashMap<>();
				}
				for (String key :ruleInfo.getEnterMap() .keySet()){
					pMap.put(key, ruleInfo.getEnterMap() .get(key));
				}
				AppConfiguration.ruleEnterMap.put(projectCode, pMap);
			}	
			AppConfiguration.RuleProjMetaMap.put(projectCode+"_"+ruleInfo.getCurrTimeStamp(), ruleInfo.getMetaMap());
			RuleDataPooledSessionFactory psf = RuleDataPooledSessionFactory.buildPooledSessionFactoryByDataRuleProj(ruleInfo.getList(),enterPoint);
			SessionDataPool sessionPool = new SessionDataPool(psf);
			AppConfiguration.AppRuleProjDataPools.put(projectCode+"_"+enterPoint, sessionPool);
			
			AppConfiguration.RuleProjMetaMap.put(projectCode, null);
			AppConfiguration.RuleFlowMetaMap.put(projectCode+"_"+enterPoint, null);
			Map<String,KieBase>  kieMap =	AppCacheInfo.kieMap.get(projectCode+"_"+ruleInfo.getCurrTimeStamp());
			if (kieMap != null) {
			   kieMap.clear();
			}
	        ruleResourceLoadService.loadProjectPmmlFuncDrl(projectCode,enterPoint,ruleInfo.getCurrTimeStamp());
	        ruleInfo = null;
		
		}
	}
	/**
	 * 根据映射关系配置，初始化规则入参信息
	 * @param paramMap
	 * @param projectCode
	 * @param enterPoint
	 * @return
	 * @throws Exception
	 */
	public String getDataMapConvert(Map<String,Object> paramMap,String projectCode,String enterPoint) throws Exception {
        Properties properties = new OrderedProperties();
        InputStream in = ResourceUtils.getURL("classpath:"+projectCode+"_"+enterPoint+".properties").openStream();
        properties.load(new InputStreamReader(in, "utf-8"));
        Map<String,Object> initMap = new HashMap<String,Object>();
        for (Entry<Object,Object> entry: properties.entrySet()) {
        	String[] param = entry.getValue().toString().split("\\.");
			if(paramMap.containsKey(param[0])) {
				Map<String,Object> tempMap = (Map<String, Object>) paramMap.get(param[0]);
				if(tempMap.containsKey(param[1])) {
					initMap.put(entry.getKey().toString(),tempMap.get(param[1]));
				}
			}
		}
        Map<String,Object> dataMap = new HashMap<String,Object>();
        for (Entry<String,Object> entry: initMap.entrySet()) {
        	String[] param = entry.getKey().toString().split("\\.");
        	Map<String,Object> dsMap = (Map<String, Object>) dataMap.get(param[0]);
			if(dsMap==null) {
				dsMap = new HashMap<String,Object>();
				dataMap.put(param[0], dsMap);
			}
			dsMap.put(param[1],entry.getValue());
		}
        return JSON.toJSONString(dataMap);
	}
	
	public static class OrderedProperties extends Properties {
        private static final long serialVersionUID = -4627607243846121965L;
        private final LinkedHashSet<Object> keys = new LinkedHashSet<Object>();
        public Enumeration<Object> keys() {
            return Collections.<Object>enumeration(keys);
        }
        @Override
        public Object put(Object key, Object value) {
            keys.add(key);
            return super.put(key, value);
        }
        @Override
        public Set<Object> keySet() {
            return keys;
        }
        @Override
        public Set<String> stringPropertyNames() {
            Set<String> set = new LinkedHashSet<String>();

            for (Object key : this.keys) {
                set.add((String) key);
            }
            return set;
        }
    }

	
	
}
